﻿using System;
using System.Collections.Generic;
using System.Text;
using CxExtension;
using JetBrains.Annotations;

//using Boo.Lang;

namespace UnityEngine
{
	public static class TransformExt
	{
		/// <summary>
		/// 确保self下面有num个transform 如果不足,则创建
		/// </summary>
		/// <param name="self"></param>
		/// <param name="num">active num</param>
		/// <param name="action">foreach active action function</param>
		/// <param name="start">instant,active forache start pos,index start 0</param>
		/// <param name="count"></param>
		public static void EnsureActiveNumChild([NotNull] this Transform self, int num,
			[NotNull] Action<Transform, int> action, int start,
			int count)
		{
			self.InstantiateNumChild(num, start, count);
			self.ActiveNum(num, start, count);
			self.ForEachiChild(action, start, num);
		}


		private static void actionDefault(Transform transf) { }

		/// <summary>
		/// instantiate num child transform,base from start index to start+count index the child
		/// </summary>
		/// <param name="self"></param>
		/// <param name="num">need instantiate num,</param>
		/// <param name="start">start pos</param>
		/// <param name="count">from start pos to start+count pos used to instantiate</param>
		public static void InstantiateNumChild(this Transform self, int num, int start,
			int count)
		{
			self.InstantiateNumChildCall(num, actionDefault, start, count);
		}
		/// <summary>
		///  instantiate num child transform,base from start index to start+count index the child
		/// </summary>
		/// <param name="self"></param>
		/// <param name="num">need instantiate num,</param>
		/// <param name="start"></param>
		public static void InstantiateNumChild(this Transform self, int num, int start)
		{
			self.InstantiateNumChildCall(num, actionDefault, start, self.childCount);
		}
		public static void InstantiateNumChild(this Transform self, int num)
		{
			self.InstantiateNumChild(num, 0, self.childCount);
		}
		public static void InstantiateNumChildCall([NotNull] this Transform self, int num, [NotNull] Action<Transform> action, int start,
		int count)
		{
			if (self == null) throw new ArgumentNullException("self");
			if (action == null) throw new ArgumentNullException("action");

			var list = self.GetChildAll();
			var i = list.Count - start;
			if (i == 0)
			{
				Debug.LogErrorFormat("transform:{0},not child,\npath:{1}", self.name, self.GetTransformPath());
				return;
			}

			if (i >= num) return;

			do
			{
				count = Mathfe.ClampRing0(count, list.Count);
				var end = Mathfe.ClampRing0(count + start, list.Count);
				for (var index = start; index < end; index++)
				{
					var it = list[index];
					var ins = Object.Instantiate(it);
					self.AddChild(ins);
					action(ins);
					i++;
					if (i >= num)
					{
						return;
					}
				}
			} while (true);
		}

		public static List<Transform> GetChildAll(this Transform self)
		{
			if (self == null) { return null; }
			var list = new List<Transform>(self.childCount);
			self.ForEachChild(it =>
			{
				list.Add(it);
			});
			return list;
		}

		public static Transform FindOrNew(this Transform self, string child, Func<Transform> newAction)
		{
			var transf = self.Find(child);
			if (transf == null)
			{
				//Debug.LogErrorFormat("{0} is null", transf);
				transf = newAction();
			}

			return transf;
		}
		public static Transform FindOrNew(this Transform self, string child)
		{
			return self.FindOrNew(child, (() =>
			{
				var transf = new GameObject(child).transform;
				transf.gameObject.name = child;

				return transf;
			}));
		}
		public static Transform FindA(this Transform self, Func<Transform, bool> finder)
		{
			if (self == null) { return null; }
			if (finder == null) { return null; }

			var leng = self.childCount;
			for (var i = 0; i < leng; i++)
			{
				var it = self.GetChild(i);
				if (finder(it))
				{
					return it;
				}
			}

			return null;
		}


		public static Transform ActiveOneA(this Transform self, int index,
			Action<Transform, bool> activeAction, int start, int count)
		{
			Transform transform = null;
			if (index < 0)
			{
				index = self.childCount + index;
			}
			self.ForEachiChild((it, i) =>
			{
				var active = index == i;
				activeAction(it, active);
				//it.SetActive(active);
				if (active)
				{
					transform = it;
				}
			}, start, count);
			return transform;
		}

		public static Transform ActiveOneA(this Transform self, int index, Action<Transform, bool> activeAction, int count)
		{
			return self.ActiveOneA(index, activeAction, 0, count);
		}
		public static Transform ActiveOneA([NotNull] this Transform self, int index, Action<Transform, bool> activeAction)
		{
			if (self == null) throw new ArgumentNullException("self");
			return self.ActiveOneA(index, activeAction, 0, self.childCount);
		}


		public static Transform ActiveOne(this Transform self, int index, int start, int count)
		{
			return self.ActiveOneA(index, (it, active) => it.SetActive(active), start, count);

		}
		public static Transform ActiveOne(this Transform self, int index, int count)
		{
			return self.ActiveOne(index, 0, count);

		}
		/// <summary>
		/// 把指定索引的child设置为active true 其他child设置为false
		/// </summary>
		/// <param name="self"></param>
		/// <param name="index">可以为负数,表示反向索引 比如 -1 表示 leng - 1</param>
		/// <returns></returns>

		public static Transform ActiveOne(this Transform self, int index)
		{
			return self.ActiveOne(index, 0, self.childCount);
		}


		public static Transform FindActiveNum(this Transform self, string childerName, int num)
		{
			Transform transform = null;
			self.Find(childerName, (it) =>
			 {
				 transform = it;
				 it.ActiveNum(num);
			 });

			return transform;
		}

		public static Transform FindActiveNum(this Transform self, string childerName, int num,
			Action<Transform, bool> activeAction)
		{
			var transf = self.Find(childerName);
			if (transf)
			{
				transf.ActiveNumA(num, activeAction);
			}

			return transf;
		}

		/// <summary>
		/// Active指定数量的child
		/// </summary>
		/// <param name="self"></param>
		/// <param name="num">可以为负数,表示反向索引 比如 -1 表示 leng - 1</param>
		/// <param name="activeAction"></param>
		/// <param name="start"></param>
		/// <param name="count"></param>
		/// <returns></returns>
		public static Transform ActiveNumA(this Transform self, int num, Action<Transform, bool> activeAction, int start, int count)
		{
			Transform transform = null;
			int ii = 0;
			self.ForEachiChild((it, i) =>
			{
				var active = ii < num;
				//it.SetActive(active);
				activeAction(it, active);
				if (active)
				{
					transform = it;
				}

				ii++;
			}, start, count);
			return transform;
		}

		public static Transform ActiveNumA(this Transform self, int num, Action<Transform, bool> activeAction, int count)
		{
			return self.ActiveNumA(num, activeAction, 0, count);
		}

		public static Transform ActiveNumA(this Transform self, int num, Action<Transform, bool> activeAction)
		{
			if (self == null) throw new ArgumentNullException("self");

			return self.ActiveNumA(num, activeAction, 0, self.childCount);
		}

		public static Transform ActiveNum(this Transform self, int num)
		{
			return self.ActiveNum(num, 0, self.childCount);
		}
		public static Transform ActiveNum(this Transform self, int num,int count)
		{
			return self.ActiveNum(num, 0, count);
		}
		public static Transform ActiveNum(this Transform self, int num,int start,int count)
		{
			return self.ActiveNumA(num, (it, value) => it.SetActive(value),start,count);
		}


		/// <summary>	
		/// 遍历指定孩子
		/// </summary>
		/// <param name="self"></param>
		/// <param name="func"></param>
		/// <param name="start"></param>
		/// <param name="count"></param>
		/// <param name="delateSage"></param>
		public static void ForEachiChild(this Transform self, Action<Transform, int> func, int start, int count, bool delateSage = false)
		{
			if (self == null) throw new ArgumentNullException("self");
			if (func == null) throw new ArgumentNullException("func");
			if (start < 0) throw new ArgumentOutOfRangeException("start:" + start);

			var leng = self.childCount;
			count = Mathfe.ClampRing(count, 0, leng);
			if (count > leng) throw new ArgumentOutOfRangeException("count:" + count);

			var end = Mathf.Clamp(start + count, 0, leng);
			if (delateSage)
			{
				var list = new List<Transform>(leng);
				for (var i = start; i < end; i++)
				{
					var it = self.GetChild(i);
					list.Add(it);
				}
				for (var i = 0; i < list.Count; i++)
				{
					var it = list[i];
					int ii = start + i;
					func(it, ii);
				}
			}
			else
			{

				for (var i = start; i < end; i++)
				{
					var it = self.GetChild(i);
					func(it, i);
				}
			}
		}

		public static void ForEachiChild(this Transform self, Action<Transform, int> func, int count)
		{
			self.ForEachiChild(func, 0, count);
		}

		public static void ForEachiChild(this Transform self, Action<Transform, int> func)
		{
			self.ForEachiChild(func, 0, self.childCount);
			//self.ForEachiChild();
		}

		public static void ForEachChild([NotNull] this Transform self, [NotNull] Action<Transform> func, int start, int count, bool delateSafe = false)
		{
			if (func == null) throw new ArgumentNullException("func");

			self.ForEachiChild((transform, i) => func(transform), start, count, delateSafe);
		}
		public static void ForEachChild(this Transform self, Action<Transform> func, int count, bool delateSafe = false)
		{
			self.ForEachChild(func, 0, count, delateSafe);
		}
		public static void ForEachChild(this Transform self, Action<Transform> func, bool delateSafe = false)
		{
			if (self == null) { return; }
			if (func == null) { return; }

			var leng = self.childCount;
			if (leng == 0)
			{
				return;
			}

			var list = new List<Transform>(leng);
			for (var i = 0; i < leng; i++)
			{
				var it = self.GetChild(i);
				list.Add(it);
			}

			for (var i = 0; i < list.Count; i++)
			{
				var it = list[i];
				func(it);
			}
		}

		public static string GetTransformPath(this Transform self)
		{
			return self.GetTransformPath(null);
		}
		public static string GetTransformPath(this Transform self, Transform relative)
		{
			var transfs = new List<Transform>();
			var it = self;
			while (true)
			{
				transfs.Add(it);
				if (it == relative || it.parent == null)
				{
					break;
				}
				else
				{
					it = it.parent;
				}
			}
			var bld = new StringBuilder();

			for (int i = transfs.Count - 1; i >= 0; i--)
			{
				it = transfs[i];
				bld.AppendFormat("{0}/", it.name);
			}

			if (transfs.Count > 0)
			{
				bld.RemoveE(-1);
			}

			return bld.ToString();
		}

		public static List<Transform> FindAll(this Transform self, Func<Transform, bool> finder, bool recursive = false)
		{
			var list = new List<Transform>();
			self.FindAll(finder, list, recursive);
			return list;
		}
		public static List<Transform> FindAll(this Transform self, Func<Transform, bool> finder, Func<Transform, bool> recursive)
		{
			var list = new List<Transform>();
			self.FindAll(finder, list, recursive);
			return list;
		}

		public static bool FindAll(this Transform self, Func<Transform, bool> finder, IList<Transform> list, bool recursive = false)
		{
			var count = list.Count;
			foreach (Transform it in self)
			{
				if (finder(it))
				{
					list.Add(it);
				}

				if (recursive)
				{
					it.FindAll(finder, list, true);
				}
			}

			return count != list.Count;
		}

		public static bool FindAll(this Transform self, Func<Transform, bool> finder, IList<Transform> list,
			Func<Transform, bool> recursiveFunc)
		{
			var count = list.Count;
			foreach (Transform it in self)
			{
				if (finder(it))
				{
					list.Add(it);
				}
				var recursiveChild = recursiveFunc(it);
				if (recursiveChild)
				{

					it.FindAll(finder, list, recursiveFunc);
				}
			}

			return count != list.Count;
		}



		public static void Find(this Transform self, string childname, Action<Transform> action)
		{
			var child = self.Find(childname);
			if (child == null)
			{
				Debug.LogWarningFormat("{0}没有找到名为:{1}的子节点", self.name, childname);
				return;
			}

			if (action != null)
			{
				action(child);
			}
		}
		/// <summary>
		/// 重置transform的位置 旋转 缩放
		/// </summary>
		/// <param name="self"></param>
		public static void Reset(this Transform self)
		{
			self.localPosition = Vector3.zero;
			self.localRotation = Quaternion.identity;
			self.localScale = Vector3.one;
		}



		public static void AddChild(this Transform self, Transform child)
		{
			child.SetParent(self, false);
		}

		/// <summary>
		/// 查找对应名称的transform 如果没有找到就创建
		/// </summary>
		/// <param name="self"></param>
		/// <param name="name"></param>
		/// <returns></returns>
		public static Transform FindChildOrCreate(this Transform self, string name)
		{
			return self.FindChildOrCreate(name, NewTransform);
		}

		public static Transform NewTransform()
		{
			var gameObject = new GameObject();
			return gameObject.transform;
		}

		public static Transform FindChildOrCreate(this Transform self, string name, [NotNull] Func<Transform> creator)
		{
			if (creator == null) throw new ArgumentNullException(nameof(creator));
			if (self == null)
			{
				return null;
			}

			var transf = self.Find(name);
			if (transf != null) return transf;

			transf = creator();
			transf.gameObject.name = name;
			transf.SetParent(self, false);

			return transf;
		}


		/// <summary>
		/// 递归查找某个名字的Transform
		/// 支持/来区分路径
		/// </summary>
		/// <param name="self"></param>
		/// <param name="name">要查找的路径</param>
		/// <returns>如果没找到返回null</returns>
		public static Transform FindChildByName(this Transform self, string name)
		{
			var child = self.Find(name);
			if (child != null)
			{
				return child;
			}

			Transform t = null;
			for (int i = 0, length = self.childCount; i < length; i++)
			{
				t = self.GetChild(i).FindChildByName(name);
				if (t != null)
				{
					return t;
				}
			}
			return null;
		}

		/// <summary>
		/// 当前坐标 进行偏移
		/// </summary>
		/// <param name="self"></param>
		/// <param name="offset">偏移量</param>
		/// <param name="space">偏移坐标系</param>
		public static void OffsetPos(this Transform self, Vector3 offset, Space space = Space.Self)
		{
			switch (space)
			{
				case Space.World:
					self.position += offset;
					break;
				case Space.Self:
					self.localPosition += offset;
					break;
				default:
					break;
			}
		}

		public static void SetEulerAngleZ(this Transform self,float z)
		{
			var angles = self.eulerAngles;
			angles.z = z;
			self.eulerAngles = angles;
		}

	}
}
